package com.example.microservice.common.utils;

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @Author: caohuijie
 * @Date: 创建日期 2018/11/19
 * @Modified By:
 * @Description: excel工具
 */
public class ExcelUtils {

    /**
     * 导出excel
     * @param sheetName 导出文件名称
     * @param datas 传入要导出的数据
     * @param response
     * @param ifNormalHumpNaming 实体类命名是否为驼峰命名法,类似getString()
     * @param columnWidth 列宽
     * @param arrTitle 题目顺序要和所表示的实体类一致
     */
    public static void exportExcel(String sheetName, List<?> datas, HttpServletResponse response,String[] arrTitle, boolean ifNormalHumpNaming,Integer... columnWidth) {
        // 导出excel表格
        // 第一步，创建一个webbook，对应一个Excel文件
        //内存中只创建1000个对象，写临时文件，当超过1000条，就将内存中不用的对象释放
        try (SXSSFWorkbook wb = new SXSSFWorkbook(100);
             OutputStream output = response.getOutputStream();) {
            // 第二步，在webbook中添加一个sheet,对应Excel文件中的sheet
            SXSSFSheet sheet = wb.createSheet(sheetName);
            // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
            SXSSFRow row = sheet.createRow(0);
            // 第四步，创建单元格，并设置值表头 设置表头居中
            CellStyle style = wb.createCellStyle();
            // sheet.setColumnWidth(0, 50* 256); // 设置列宽，20个字符宽
            if (columnWidth.length > 0 && columnWidth[0] > 0) {
                sheet.setDefaultColumnWidth(columnWidth[0]);
            } else {
                sheet.setDefaultColumnWidth(30);
            }

            Class<?> clazzz = datas.get(0).getClass();
            for (int i = 0; i < arrTitle.length; i++) {
                SXSSFCell cell = row.createCell(i);
                cell.setCellValue(arrTitle[i]);
                cell.setCellStyle(style);
            }
            //记录额外创建的sheet数量,excel 导出数据有限制65535条
            int index = 0;
            //第五步，写入实体数据 实际应用中这些数据从数据库得到，
            for (int i = 0; i < datas.size(); i++) {
                if (i != 0 && (i) % 300000 == 0) {
                    sheet = wb.createSheet(sheetName + index);
                    sheet.setDefaultColumnWidth(30);
                    row = sheet.createRow(0);
                    for (int k = 0; k < clazzz.getDeclaredFields().length; k++) {
                        SXSSFCell cell = row.createCell(k);
                        Field field = clazzz.getDeclaredFields()[k];
                        cell.setCellValue(field.getName());
                        cell.setCellStyle(style);
                    }
                    index++;
                }
                row = sheet.createRow((i + 1) - (index * 300000));
                Class<?> clazz = datas.get(i).getClass();
                // 第四步，创建单元格，并设置值+ detail +
                for (int cellIndex = 0; cellIndex < clazz.getDeclaredFields().length; cellIndex++) {
                    Field field = clazz.getDeclaredFields()[cellIndex];
                    //获取是否可访问
                    boolean flag = field.isAccessible();
                    //设置该属性总是可访问
                    field.setAccessible(true);
                    // 拿到该属性的getter方法
                    /**
                     * 这里需要说明一下：他是根据拼凑的字符来找你写的getter方法的
                     * 在Boolean值的时候是isXXX（默认使用ide生成getter的都是isXXX）
                     * 如果出现NoSuchMethod异常 就说明它找不到那个gettet方法 需要做个规范
                     */
                    Method m = null;
                    if (ifNormalHumpNaming){
                        m = clazz.getMethod("get" + field.getName().substring(0,1).toUpperCase()+field.getName().substring(1));
                    }else{
                        m= clazz.getMethod("get" + field.getName());
                    }
                    // 调用getter方法获取属性值
                    Object val = (Object) m.invoke(datas.get(i));
                    row.createCell(cellIndex).setCellValue(val == null ? "" : val.toString());
                    //还原可访问权限
                    field.setAccessible(flag);
                }
            }
            // 第六步，将文件存到指定位置
            String fileName = sheetName;
            System.setProperty("sun.jnu.encoding", "utf-8");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes(), "iso-8859-1") + ".xlsx");
            response.setContentType("application/msexcel");
            wb.write(output);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
